#include "Determinant.h"
#include"Space.h"


Determinant::Determinant(int n)
{
	this->n = n;
	this->data = Space::CreateDouble(n, n);
}


Determinant::~Determinant()
{
	Space::DeleteDouble(data, n);
}

void Determinant::SetValues(double * data)
{
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			this->data[i][j] = data[i*n + j];
		}
	}
}

double Determinant::GetValue()
{
	return GetValue(*this);
}

Determinant& Determinant::GetChild(int i, int j, int n)
{
	Determinant* res = new Determinant(n);
	for (int x = 0; x < n; x++)
	{
		for (int y = 0; y < n; y++)
		{
			res->data[x][y] = this->data[i + x][j + y];
		}
	}
	return *res;
}

Determinant & Determinant::Minor(int i, int j)
{
	Determinant* res = new Determinant(n - 1);
	for (int x = 0; x < n - 1; x++)
	{
		for (int y = 0; y < n - 1; y++)
		{
			if (x < i)
			{
				if (y < i)
					res->data[x][y] = this->data[x][y];
				else
					res->data[x][y] = this->data[x][y + 1];
			}
			else
			{
				if (y < i)
					res->data[x][y] = this->data[x + 1][y];
				else
					res->data[x][y] = this->data[x + 1][y + 1];
			}
		}
	}
	return *res;
}

double Determinant::GetValue(Determinant & D)
{
	double res = 0;
	if (D.n == 1)
	{
		res = D.data[0][0];
	}
	else
	{
		if (D.n % 2 == 0)
		{
			int wA = D.n / 2;
			Determinant A = D.GetChild(0, 0, wA);
			Determinant B = D.GetChild(0, wA, wA);
			Determinant C = D.GetChild(wA, 0, wA);
			Determinant D = D.GetChild(0, wA, wA);
			res = GetValue(A)*GetValue(D) - GetValue(B)*GetValue(C);
		}
		else
		{
			int s = 1;
			for (int j = 0; j < D.n; j++)
			{
				res += (s*D.data[0][j] * GetValue(D.Minor(0, j)));
				s = -s;
			}
		}		
	}
	return res;
}
